package com.fallsvc.re.networkprogramming.lock.readwrite;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo {
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
    private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
    private int sharedData = 0;

    // 读操作
    public int readData() {
        readLock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " 读取数据: " + sharedData);
            Thread.sleep(100); // 模拟读取耗时
            return sharedData;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return -1;
        } finally {
            readLock.unlock();
        }
    }


    private volatile boolean update = false;
    private int data = 0;
    // 写操作
    public void writeData(int newValue) {
        writeLock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " 写入数据: " + newValue);
            Thread.sleep(200); // 模拟写入耗时
            sharedData = newValue;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            writeLock.unlock();
        }
    }
    public void processData() {
        readLock.lock();
        if (!update) {
            // 必须先释放读锁才能获取写锁 // 锁不能升级
            readLock.unlock();

            writeLock.lock();
            try {
                // 再次检查，防止其他线程已经修改
                if (!update) {
                    // 准备数据
                    data = prepareData();
                    update = true;
                }
                // 锁降级：在释放写锁之前获取读锁
                readLock.lock();
            } finally {
                writeLock.unlock(); // 写锁降级为读锁
            }
        }

        try {
            // 使用数据
            useData(data);
        } finally {
            readLock.unlock();
        }
    }

    private int prepareData() {
        System.out.println("准备数据...");
        return 42;
    }

    private void useData(int data) {
        System.out.println("使用数据: " + data);
    }
}